package de.hwrberlin.remo.diagram.custom.dialogs;

import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.ProgressBar;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.forms.events.ExpansionAdapter;
import org.eclipse.ui.forms.events.ExpansionEvent;
import org.eclipse.ui.forms.widgets.ExpandableComposite;
import org.eclipse.ui.forms.widgets.Form;
import org.eclipse.ui.forms.widgets.FormToolkit;

import de.hwrberlin.remo.algorithm.steps.AlgorithmStep;
import de.hwrberlin.remo.algorithm.util.AlgorithmDebugger;

import de.hwrberlin.remo.diagram.custom.util.ImageUtil;
import de.hwrberlin.remo.diagram.custom.util.Images;

public class AlgorithmDebugDialog extends Dialog {

	private AlgorithmDebugger debugger;
	private String algorithmName;

	private Form form;
	
	private Button buttonFirst;
	private Button buttonPrevious;
	private Button buttonNext;
	private Button buttonLast;

	private ProgressBar progressBar;
	private Label stepLabel;
	private Label explanationLabel;
	
	public AlgorithmDebugDialog(Shell parentShell, AlgorithmDebugger executer,
			String algorithmName) {
		super(parentShell);
		setBlockOnOpen(true);
		setShellStyle(getShellStyle());
		
		this.algorithmName = algorithmName;
		this.debugger = executer;
	}

	@Override
	protected Point getInitialSize() {
		return new Point(350, 150);
	}
	
	@Override
	protected Layout getLayout() {
		return GridLayoutFactory.fillDefaults().margins(0, 0).spacing(0,0).create();
	}
	
	///////////
	/* GUI   */

	@Override
	protected Control createDialogArea(final Composite parent) {
		FormToolkit toolkit = new FormToolkit(parent.getDisplay());
		GridDataFactory stdGridData = GridDataFactory.fillDefaults().grab(true, false);

		GridLayoutFactory parentGridLayout = GridLayoutFactory.fillDefaults().margins(0, 0).spacing(0, 0);
		parentGridLayout.applyTo(parent);
		
		// -------------------------------------------------------------------------------------
		
		form = toolkit.createForm(parent);
		GridDataFactory.fillDefaults().grab(true, true).applyTo(form);
		GridLayoutFactory.fillDefaults().spacing(0, 5).extendedMargins(10, 10, 10, 10).applyTo(form.getBody());
		
		progressBar = new ProgressBar(form.getBody(), SWT.HORIZONTAL);
		progressBar.setMaximum(debugger.getStepCount());
		progressBar.setMinimum(0);
		
		stdGridData.applyTo(progressBar);
		
		stepLabel = toolkit.createLabel(form.getBody(), "");
		stepLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

		stdGridData.applyTo(stepLabel);
		
		// --------------------------------------------------------------------------------------
		
		final ExpandableComposite descriptionComposite = toolkit.createExpandableComposite(form.getBody(), 
				ExpandableComposite.TREE_NODE | ExpandableComposite.CLIENT_INDENT);
		descriptionComposite.setText("Explanation");
		descriptionComposite.setLayout(new GridLayout());
		GridDataFactory.fillDefaults().grab(true, true).applyTo(descriptionComposite);
		
		explanationLabel = toolkit.createLabel(descriptionComposite, "", 
				SWT.READ_ONLY | SWT.V_SCROLL | SWT.WRAP | SWT.FLAT);
		descriptionComposite.setClient(explanationLabel);
		
		descriptionComposite.addExpansionListener(new ExpansionAdapter() {
			@Override
			public void expansionStateChanged(ExpansionEvent e) {
				Point currentSize = descriptionComposite.getSize();

				int computedY = descriptionComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT).y;
				int differenceY = computedY - currentSize.y;
				
				if(e.getState()) {
					differenceY += 45;
				}
				
				descriptionComposite.setSize(currentSize.x, computedY);
				
				Point currentShellSize = getShell().getSize();
				currentShellSize.y += differenceY;
				getShell().setSize(currentShellSize);
			}
		});
		
		parent.getShell().setText(algorithmName);
		
		refreshStepValues();
		return form;
	}
	
	@Override
	protected void createButtonsForButtonBar(Composite parent) {		
		Image imageFirst    = ImageUtil.getImage(Images.FIRST_IMAGE);
		Image imagePrevious = ImageUtil.getImage(Images.PREVIOUS_IMAGE);
		Image imageNext     = ImageUtil.getImage(Images.NEXT_IMAGE);
		Image imageLast     = ImageUtil.getImage(Images.LAST_IMAGE);
		
		FormToolkit toolkit = new FormToolkit(parent.getDisplay());
		parent.setLayout(new GridLayout(4, true));
		
		buttonFirst    = toolkit.createButton(parent, "", SWT.PUSH | SWT.FLAT);
		buttonFirst.setImage(imageFirst);
		buttonFirst.addSelectionListener(navigationListener);
		
		buttonPrevious = toolkit.createButton(parent, "", SWT.PUSH | SWT.FLAT);
		buttonPrevious.setImage(imagePrevious);
		buttonPrevious.addSelectionListener(navigationListener);
		
		buttonNext 	   = toolkit.createButton(parent, "", SWT.PUSH | SWT.FLAT);
		buttonNext.setImage(imageNext);
		buttonNext.addSelectionListener(navigationListener);
		
		buttonLast     = toolkit.createButton(parent, "", SWT.PUSH | SWT.FLAT);
		buttonLast.setImage(imageLast);
		buttonLast.addSelectionListener(navigationListener);
		
		refreshStepValues();
		refreshButtons();
	}
	
	/////////////////////
	/* Refresh methods */
	
	private void refreshStepValues() {
		// Update progress bar
		progressBar.setSelection(debugger.getCurrentStepNumber());

		String labelText = debugger.getCurrentStepNumber() + " / " + debugger.getStepCount() + ": ";
		String descriptionText = "";
		
		if(debugger.isStart()) {
			labelText += "Start";
		
		} else {
			AlgorithmStep currentStep = debugger.getCurrentStep();
			
			if(currentStep != null) {
				String label = currentStep.getLabel();
				String description = currentStep.getExplanation();
				
				if(label != null) {
					labelText += label;
				}
				
				if(description != null) {
					descriptionText = description;
				}
			}
		}
		
		stepLabel.setText(labelText);
		explanationLabel.setText(descriptionText);
		
		form.getBody().layout();
	}
	
	private void refreshButtons() {
		buttonFirst.setEnabled(!debugger.isStart());
		buttonPrevious.setEnabled(!debugger.isStart());
		buttonNext.setEnabled(!debugger.isEnd());
		buttonLast.setEnabled(!debugger.isEnd());
	}
	
	///////////////
	/* Listeners */
	
	private SelectionListener navigationListener = new SelectionAdapter() {
		public void widgetSelected(SelectionEvent e) {
			if(e.widget == buttonFirst) {
				debugger.gotoFirst();
				
			} else if(e.widget == buttonPrevious) {
				debugger.back();
				
			} else if(e.widget == buttonNext) {
				debugger.next();
				
			} else if(e.widget == buttonLast) {
				debugger.gotoLast();
			}
			
			refreshStepValues();
			refreshButtons();
		};
	};
}